#include <dpmi.h>
#include <go32.h>
#include "ints.h"
#include <pc.h>

int install_asm_irq_handler(int irq, void (*irq_func)(void), _go32_dpmi_seginfo *old_irq)
{
	// vari�veis para os endere�os dos handlers
	_go32_dpmi_seginfo  new_irq;

	// endere�o do handler original
	_go32_dpmi_get_protected_mode_interrupt_vector(IRQ_VECTOR(irq), old_irq);
	new_irq.pm_selector = _go32_my_cs( ); // selector do c�digo
	new_irq.pm_offset = (unsigned long) irq_func; // endere�o do novo handler
	// instala��o do handler na IDT
	_go32_dpmi_set_protected_mode_interrupt_vector(IRQ_VECTOR(irq), &new_irq);
	return 0;
}

void reinstall_asm_irq_handler(int irq, _go32_dpmi_seginfo *old_irq)
{
	_go32_dpmi_set_protected_mode_interrupt_vector(IRQ_VECTOR(irq), old_irq);
}

int install_c_irq_handler(int irq, void (*irq_func)(void),
			    _go32_dpmi_seginfo *old_irq)
{
	//devolve o vector correspondente ao IRQ pretendido
	int vector = IRQ_VECTOR(irq);

	//endereco do handler original
	if(_go32_dpmi_get_protected_mode_interrupt_vector(vector, old_irq)) return -1;

	//variavel para o endereco do handler
	_go32_dpmi_seginfo new_irq;
	new_irq.pm_selector = _go32_my_cs(); // selector do codigo
	new_irq.pm_offset = (unsigned long)irq_func; // endereco do novo handler

	//prepara função assembly para chamar função C
	if(_go32_dpmi_allocate_iret_wrapper(&new_irq)) return -1;

	// instalacao do handler na IDT
	if(_go32_dpmi_set_protected_mode_interrupt_vector(vector, &new_irq)) return -1;
	return 0;
}



void reinstall_c_irq_handler(int irq, _go32_dpmi_seginfo *old_irq)
{
	//devolve o vector correspondente ao IRQ pretendido
	int vector = IRQ_VECTOR(irq);

	//guarda apontador para o handler actual
	_go32_dpmi_seginfo new_irq;
	_go32_dpmi_get_protected_mode_interrupt_vector(vector, &new_irq);

	//repoe o handler original
	_go32_dpmi_set_protected_mode_interrupt_vector(vector, old_irq);

	//liberta função assembly
	_go32_dpmi_free_iret_wrapper(&new_irq);
}


int disable_irq(int irq)
{
	ushort pic;
	if ( irq < 8 )
		pic = PIC1_MASK;
	else
		pic = PIC2_MASK;
	
	int previous = inportb(pic);
	outportb(pic, previous | IRQ_MASK_BIT(irq) );
	return previous;
}

void enable_irq(int irq)
{
	ushort pic;
	if ( irq < 8 )
		pic = PIC1_MASK;
	else
		pic = PIC2_MASK;
	outportb(pic, inportb(pic) & ~(IRQ_MASK_BIT(irq)) );
}


static Byte state_pic1;
static Byte state_pic2;

void enable_int()
{
	outportb(PIC1_MASK, state_pic1);
	outportb(PIC2_MASK, state_pic2);
}

void disable_int()
{
	state_pic1 = inportb(PIC1_MASK);
	state_pic2 = inportb(PIC2_MASK);
	outportb(PIC1_MASK, 0xFF); // Inibe as interrupções
	outportb(PIC2_MASK, 0xFF);
}
